PROGRESS
(Version 8.2A)
BASIC QUERY COURSE
Updated May 2005

Table of Contents
	
CHAPTER 1: Database Concepts	1-1
Database	1-1
Table	1-1
Record:  (Row)	1-1
Field:  (Column)	1-1
Key:  (Unique Identifier)	1-2
Index	1-2
The Relational Model	1-2
CHAPTER 2: Using the Procedure Editor	2-1
Creating a New Program	2-1
Opening an Existing Program	2-2
Saving a Program	2-3
Editing a Program	2-4
Entering Text	2-4
Selecting Text	2-4
Cutting, Copying and Pasting Text	2-4
Inactivating or Commenting Text	2-5
Searching Text	2-5
Inserting a Field Name into a Program	2-6
Checking, Compiling, and Running a Program	2-7
Checking Program Syntax	2-7
Running a Program	2-7
Edit Buffers	2-8
Viewing Open Edit Buffers	2-8
Viewing Database Tables	2-8
CHAPTER 3: Accessing the Database	3-1
Retrieving Records from the Database	3-1
FOR EACH	3-1
WHERE  expression	3-2
BY  expression	3-3
NO-LOCK	3-3
FIND	3-3
WHERE  expression	3-4
OF  table-name	3-5
Controlling Error Processing with FIND	3-6
NO-ERROR	3-6
CHAPTER 4: Operators and Functions	4-1
Operators	4-1
Arithmetic Operators	4-1
Comparison Operators	4-1
Keywords	4-1
Functions	4-2
Precedence	4-3
CHAPTER 5: Conditional Processing	5-1
If…Then…Else	5-1
ELSE  {block/statement}	5-1
Using Multiple Statements with IF	5-2
Nesting Multiple IF Statements	5-3
CHAPTER 6: Define Statement	6-1
Defining Variables	6-1
AS  datatype	6-1
FORMAT  format	6-1
DECIMALS  n	6-2
INITIAL  value	6-2
LABEL  string	6-2
LIKE  field	6-2
NO-UNDO	6-3
Assigning Values to Variables	6-3
Assigning Values to Variables in Groups	6-4
Defining Record Buffers	6-5
Defining Output Streams	6-6
CHAPTER 7: Generating Reports	7-1
Directing Output to a File	7-1
STREAM  stream-name	7-1
Parameters	7-1
DISPLAY Statement	7-2
Expression  [format-phrase]	7-2
Aggregate-phrase	7-3
SPACE [(n)]	7-3
SKIP [(n)]	7-3
WITH  [WIDTH n / n COLUMN]	7-3
Defining Output Streams	7-4
Aggregating Totals/Performing Mathematical Functions	7-5
LABEL  function-identifier	7-5
BY  break-group	7-5
FIRST-OF and LAST-OF Functions	7-6
Using ACCUMULATE and ACCUM	7-6
EXPORT Statement	7-7
STREAM  stream-name	7-7
DELIMITER  character	7-7
Index	I-1

CHAPTER 1:	
	Database Concepts
	
PROGRESS uses a relational database structure to organize data.  A relational database system relates different data tables to each other and, therefore, is capable of querying these tables to extract information.  A database file contains the database definitions and data.  Database definitions include table names, field names, key fields, and indexes.
	Database
A database is an electronic filing system for organizing and storing data.  It is like a filing cabinet whose physical space is in a computer.  Its basic elements are tables, records, fields, indexes and keys.
	Table
A table is a collection of logically related information about a specific subject (Example:  Admin Table).
	FIELDS (Columns)
UNUM	RNUM	LEGAL NAME	DBA	ADDRESS	
0500	00000	  1st Business	  Example 1	  1st Avenue	Records
(Rows)	
1000	00000	  2nd Business	  Example 2	  2nd Street		
1500	00000	  3rd Business	  Example 3	  3rd Drive	
1500	00101	  1st Subunit	  Example 4	  4th Circle	
	Record:  (Row)
A record is a single occurrence of the information in a table; a collection of pieces of information about one thing.  In the example shown above, the single occurrence contains all of the information relative to a single UNUM, RNUM for that table.  It is like a folder in a file drawer where files are organized by UNUM, RNUM.  An individual form contains general (admin) information on the business.
	Field:  (Column)
A field is an individual piece of information—the smallest unit of information.  In the example, the individual items of information relate to a single employer (unum, rnum, Legal Name, DBA, Address).  These would be the specific items of information on a form.
	Key:  (Unique Identifier)
In PROGRESS there are two types of keys, primary and foreign.  A primary key is a field or group of fields whose value uniquely identifies each record in a table.  Only one record is allowed to have a particular primary key, thus preventing duplicate records in the table.

A foreign key is a field or group of fields that is common to more than one table, but must be the primary key of one of the tables.  The combination of the primary and foreign keys provides the link between tables; it serves as a cross-reference.
	Index
An index in a database functions like an index tab on a file folder.  It is a pointer to an identifying field(s) that makes it easier to find information.  The index is used as the basis for retrieving and sorting records.  It also determines whether the organization of the records is numeric or alphabetical, ascending or descending.  In the example on the previous page, the admin table is primarily indexed on UNUM, RNUM, which causes the file to be organized in numeric order.

Combinations of fields can be indexed together to allow sorting in different ways.  Again, using the admin table as an example, the following indexes are available:
	Primary index:	ascending unum rnum
	Other indexes:	ascending by unum only
		ascending ein unum rnum 
		ascending legal name (alphabetic organization)
If no index is specified when processing records, the system defaults to the primary index for retrieval and sorting.
	The Relational Model
PROGRESS utilizes a relational database structure for organizing its tables.  As such, it stores data in tables and lets you cross-reference the tables using a common field or fields, the foreign key.

An example of this is the relationship between the admin and quarterly tables in the WIN‑202v2 database.  The fields common to both tables are the unum and rnum and are the means by which a cross-reference is established.  This combination is a unique identifier in the admin table, but not in the quarterly table.  Therefore, many quarterly records can exist for each admin record.  The year and quarter are used to create uniqueness in the quarterly file.  The impact this has on the retrieval of records will be discussed in Chapter 3: Accessing the Database.
	
CHAPTER 2:	
	Using the Procedure Editor
	
You can use the Procedure Editor to create, modify and run PROGRESS code (procedures).  When you start the Procedure Editor, it displays a screen titled “Untitled:1” (see below figure).  This screen has a menu bar from which you can access the functions and tools that you need to work with your program.  The cursor, in the upper left corner of the screen, identifies where you can begin to type your query code.  Scroll bars on the bottom and right of the screen enable scrolling vertically and horizontally to view your program code.

Menu Bar

	Creating a New Program
To create a new program, simply start the Procedure Editor and begin typing.  In order to keep the program for future use, you will need to save the finished version (select File  Save As from the menu bar).
Exercise 1:
1.	Open the Procedure Editor and type the following:
FOR EACH admin NO-LOCK:
DISPLAY unum rnum WITH 1 COLUMN.
END.
2.	Save the program as “newprog.p”.  (Refer to Saving a Program on page 5.)
3.	Close the program by selecting FileClose from the menu bar.
	
	Opening an Existing Program
To open a program that was previously saved, select FileOpen from the Procedure Editor menu bar.  You will be presented with the “Open” screen shown below.

The “Look in:” pull-down list is used to select the directory in which your program exists.  If it does not display the correct directory, you will need to use the pull-down arrow or the icon displaying a folder with an up arrow to navigate to the correct directory.

You can select the program you want to use in one of two ways:
1.	Highlight the program name and select the [Open] button with a left-click.
2.	Left double-click on the program name.

The selected program code will be displayed in the available screen area of the Procedure Editor window.  From here you may view, edit or run your program.
Exercise 2:
1.	Open the program “newprog.p” using the FileOpen menu selection.  Try opening it both ways.
2.	Close the program by selecting FileClose from the menu bar.

	Saving a Program
To save a newly created program, select FileSave from the Procedure Editor menu bar.  You will be presented with the “Save As” screen below.

The “Save in:” pull-down list is used to select the directory in which you want to save your program.  If it does not display the correct directory, you will need to use the pull-down arrow or the icon displaying a folder with an up arrow to navigate to the correct directory.
•	Enter the name of your program into the “File name:” field with an extension of “.p”.
•	Choose the [Save] button to save the program or the [Cancel] button to exit without saving.
•	To save changes to a previously existing program, select FileSave from the Procedure Editor menu bar.  The changes will automatically be saved in the program under the same name.
•	To create a new program from a previously existing program, select FileSave As, give the program a new name in the “File name:” field and choose the [Save] button.
Exercise 3:
1.	Open “newprog.p”.
2.	Choose FileSave from the menu bar.
3.	The program has been saved again as “newprog.p”.
4.	Choose FileSave As from the menu bar.
5.	Save the program as “copyprog.p”.
6.	Open “copyprog.p” in the Procedure Editor.
7.	Close both programs.
	
	Editing a Program
The Procedure Editor enables you to perform various editing functions:
•	Enter text
•	Select text
•	Cut, copy, and paste text
•	Inactivate or comment text
•	Search for a word, phrase or character string
•	Insert field names from the data dictionary
	Entering Text
To enter program text, simply begin typing.  The cursor identifies the beginning point of your text.  You can reposition the cursor by using the mouse pointer.
	Selecting Text
You can select a block of text when you want to cut (delete), copy, or inactivate a portion of code.  Selecting text in the Procedure Editor works the same as with most word processing packages.  To select a block of text, move the mouse pointer to the starting point and press the left mouse button to set the cursor.  Continue holding down the left mouse button and drag the pointer over the entire block of text.  Release the mouse button.  The highlighted portion of text will be affected by the function you perform.
	Cutting, Copying and Pasting Text
You can cut or copy and paste a block of text as outlined below:
1)	Select the block of text you want to cut or copy (see above for selecting text).
2)	From the Procedure Editor menu bar:
a)	Choose EditCut (CTRL+X) to cut the text.
b)	Choose EditCopy (CTRL+C) to copy the text.
3)	Place the cursor where you want to insert the text and choose EditPaste (CTRL+V).

The text will be inserted and the cursor repositioned at the end of the text block.
	Inactivating or Commenting Text
You can inactivate (comment), rather than delete, lines of code within your program.  This is generally used:
•	To add descriptive or clarifying information to the program.
•	To vary the lines of code and run the same program against different information.
•	During testing for debugging purposes.

To comment a block of text, do the following:
1.	Select the block of text you want to comment (see previous page for selecting text).
2.	Right-click on the mouse to activate a pop-up function window.
3.	Select FormatComment.
4.	The Procedure Editor will enclose the block of code within comment identifiers ( /*, */ )  and position the cursor at the end of the block of text.
Example:
/* Looks for all accounts having employment of 500 or more for the specified year/qtr. */
	Searching Text
You can search through your program for a word, phrase or character string using the Search menu option.  This option allows you to search in several ways.

•	Choose SearchFind (CTRL+F) to find a specified character string.
•	Choose SearchFind Next (F9) to find the next occurrence of the text.
•	Choose SearchFind Previous (SHIFT+F9) to find the previous occurrence of the text.
•	Choose SearchReplace (CTRL+R) to find a specified set of characters and replace it with something else.
	Inserting a Field Name into a Program
You can insert a field name directly from a table definition at the cursor’s position by doing the following:
1.	Place the cursor where the field name is to be inserted.
2.	Choose EditInsert Fields from the menu bar.  You will be presented with the “Field Selector” screen below:

3.	The “Field Selector” screen contains three columns:  Databases, Tables, and Fields.  It also contains several buttons and a radio set where you can specify prefixes to include with the field names.
•	Databases:  Since you will only be connected to one database, WIN202v2, you do not need to select a database—it is your system default.
•	Tables:  This column lists, alphabetically, all of the tables available within the WIN-202 system.  To select the table from which you will choose fields, highlight the table name.  If the table you need to use is not in the window, scroll down until you locate it, then highlight its name.
•	Fields:  This column lists, alphabetically, all of the fields available within the selected table.  To choose a specific field, left-click on it to highlight its name.  You can choose several fields at a time in the same manner.  To choose all of the fields within a table, left-click on the [Select All] button.
•	Prefixes:  Three options are available for including prefixes on your field names:  None, Table, and Database.Table.
o	None:  This is the default and will include only the field name.
o	Table:  This option will include the table name as a prefix with each field name (i.e., admin.legal_n).
o	Database.Table:  This option will include the database name and table name with each field name.  You will not need to use this option, since you are only connected to one database.
4.	When you are done making your selections on the “Field Selector” screen, click the [OK] button.  Your fields will be inserted into your program at the point identified by the cursor.
Exercise 4:
1.	Open “copyprog.p”.
2.	Using the Field Selector screen, add the legal_n, dba, tax_str, tax_cty, tax_st and tax_zip to the DISPLAY statement.  These fields will need to be added BEFORE the “WITH 1 COLUMN” phrase.
3.	Save “copyprog.p”.
	
	Checking, Compiling, and Running a Program
Use Compile on the Procedure Editor’s menu bar to check the program syntax and run the program.
	Checking Program Syntax
You can check the syntax of your program before running it to make sure the PROGRESS statements you have typed are grammatically correct.  To do this, select CompileCheck Syntax from the menu bar or use [SHIFT+F2].  The program syntax will be checked and PROGRESS will display any error messages in the Compiler Messages dialog box.  The message provides a short description of the error, an error number, and the program line number in which the error occurred.
•	To get additional information on the messages, select HelpRecent Messages from the menu bar.  This will allow you to scroll sequentially through the error messages generated by the syntax check on the program.
•	You can obtain information on a specific error message by selecting HelpMessages from the menu bar and entering the message number in the box.  Select the [View Message] button to see the message description. 
•	All errors will need to be corrected before PROGRESS will allow you to run the program.
	Running a Program 
After you have corrected all of the syntax errors, run the program by selecting CompileRun from the menu bar or using [F2].  The Procedure Editor temporarily compiles the program, runs it, and displays the results in the Procedure Editor—Run window.  A message bar at the bottom of the window provides information about the status of the run and how to return to the Procedure Editor.
Exercise 5:
1.	Open “copyprog.p”.
2.	Check the syntax.  If there are any errors, correct them.
3.	Run the program.
	
Exercise 5A:
Create syntax errors and use the Recent Messages/Messages options to view the errors.
	
	Edit Buffers
An edit buffer is temporary space where you can work with a PROGRESS procedure.  The Procedure Editor allows you to work with several procedures simultaneously by creating an edit buffer for each procedure.  An edit buffer can contain a new, unsaved procedure or an existing procedure.  To this point you have been working with the “Untitled:1” edit buffer for new programs OR the edit buffer for your opened procedure.  The ability to use multiple edit buffers enables you to have both of them open at the same time.  You can cut, copy, and paste between buffers, making it easy to isolate or reuse portions of code.
	Viewing Open Edit Buffers
The Procedure Editor creates a buffer each time you use the New or Open option.  To view a list of all edit buffers for your current session, select BufferList from the menu bar.  The active buffer is highlighted in the list.  You can change buffers by selecting it from the list and clicking [OK] or by double-clicking on the item.  You can also change buffers by selecting BufferPrevious or BufferNext from the menu or by pressing [F7] until you reach the desired buffer.
Exercise 6: 
1.	Open “newprog.p” in the Procedure Editor.
2.	Open “copyprog.p” in the Procedure Editor.
3.	Select FileNew from the Procedure Editor menu and type something.
4.	Using the Buffer menu options, practice moving among the edit buffers.
	
	Viewing Database Tables
Sometimes it is helpful to be able to view the contents and relationships of the database tables, especially when you need to join tables.  You can do this by using the Tools menu option in the Procedure Editor.

When you select ToolsData AdministrationDatabaseReports, PROGRESS presents several options for viewing the database structure.  You can choose to produce a variety of reports for a single table or all tables.  The different reports provide differing levels of detail on the selected table(s).  The Table Relations option identifies the “OF” relationships for the specified table for use in the FIND statement.  It also identifies the common field(s) on which the relationship is based.
Exercise 7:
1.	Select ToolsData AdministrationDatabaseReports from the Procedure Editor menu.
2.	Investigate the options, displaying the results to your terminal.

	
CHAPTER 3:	
	Accessing the Database
	
	PROGRESS provides several commands to access the database for different purposes.  This chapter discusses the commands that will enable you to query the database to generate reports.
	Retrieving Records from the Database 
You will use one of two basic commands to read (retrieve) records from the database:
FOR EACH and FIND.
•	FOR EACH:  Sequentially retrieves each record in a table in the order of the specified index.
•	FIND:  Retrieves one specific record.
	FOR EACH
The FOR EACH statement will read each record in the identified table that meets the specified criteria.  If no criteria are specified, every record in the table will be retrieved.
Statement syntax:
	FOR    EACH     table-name     [USE-INDEX index]     [WHERE  expression]
	NO-LOCK     [BREAK]     [BY  expression   [DESCENDING]]

In its simplest form, the FOR EACH statement contains the following elements:
FOR EACH table-name:
END.
Note: The END statement is necessary to close the repetitive processing of the FOR EACH statement.  It tells PROGRESS that the processing associated with the retrieved record has been completed and a new record needs to be retrieved.

In the statement above, no processing has taken place on the retrieved records.  The following statements illustrate where that processing would take place:
	FOR EACH table-name:
	Processing goes here.
	END.
EXAMPLE 1:
FOR EACH admin NO-LOCK:
	DISPLAY unum rnum legal_n.
END.
Note: Example 1 will read every record in the admin table.  The DISPLAY statement causes the identified fields to be displayed on the user’s screen.
Exercise 1:
1.	Using the ADMIN table, read each record and display the account number (unum, rnum), legal name (legal_n), city (tax_cty) and zip code (tax_zip).
Note:  Make sure to include the END statement.
2.	Check the syntax and run the program.
3.	Save the program as “foreach1.p”.
	
	WHERE  expression
The WHERE clause limits record retrieval based on a condition (expression).
FOR EACH  table-name  WHERE  condition  NO-LOCK:
EXAMPLE 2:
FOR EACH admin WHERE rnum = 0 NO-LOCK:
	DISPLAY unum rnum legal_n.
END.
Note: Example 2 retrieves ADMIN records whose rnum is 0.  No subunits will be retrieved.
EXAMPLE 3:
FOR EACH admin WHERE rnum > 0 NO-LOCK:
	DISPLAY unum rnum legal_n.
END.
Note: Example 3 retrieves ADMIN records whose rnum is greater than 0.  Only subunits will be retrieved.
Exercise 2:
1.	Modify the program from Exercise 1 to select records whose initial liability date (init_liab_dte) is after (>) 12/31/2002.  To check your query, add init_liab_dte to the display statement.
2.	Check the syntax and run the program.
3.	Save the program as “foreach2.p”.
	
	BY  expression
The BY clause sorts records in the order specified by the value of expression.
•	Ascending order is the default.  Descending must be specified if descending order is desired.
•	Multiple BY options can be used to do multi-level sorting.
EXAMPLE 4:
FOR EACH  admin NO-LOCK BY tax_zip:
Note: Example 4 will result in the retrieved records being sorted in ascending zip code order.
EXAMPLE 5:
FOR EACH admin WHERE rnum = 0 NO-LOCK BY tax_zip descending:
	DISPLAY unum rnum legal_n tax_zip.
END.
Note: Example 5 will result in:
•	Only records with an rnum of 0 being retrieved.
•	The retrieved records being sorted in descending zip code order.
•	unum, rnum, legal name, and tax zip code being displayed on the screen.
Exercise 3:
1.	Modify the program from Exercise 2 to sort retrieved records by initial liability date in descending order.
2.	Check the syntax and run the program.
3.	Save the program as “foreach3.p”.
	
	NO-LOCK
The NO-LOCK keyword, although optional, should always be used.  The NO-LOCK keyword causes records to be accessed in “read only” mode and enables several users to access the same record at the same time.

PROGRESS uses SHARED-LOCK by default, allowing a situation, called a “Deadly Embrace”, which will lock up the entire database and prevent further access.  Therefore, we recommend that you not allow PROGRESS to default.
	FIND
The FIND statement retrieves a single record (1) from the database.
Statement syntax:
FIND     [FIRST/NEXT/PREV/LAST]     table-name     [OF table-name] 
            [WHERE expression]     [USE-INDEX index]     NO-LOCK 
In its simplest form, the FIND statement contains the following elements:
FIND     [FIRST/NEXT/PREV/LAST]     table-name.

Since the FIND statement only retrieves a single record, it does not create a repetitive read like the FOR EACH statement does.  Therefore, the FIND statement does not require an END statement to close its associated processing.

As with the FOR EACH, you need to tell PROGRESS what processing you want to take place once the record is found.
FIND     [FIRST/NEXT/PREV/LAST]     table-name.
Processing goes here.
EXAMPLE 6:
FIND FIRST admin NO-LOCK.
DISPLAY unum rnum legal_n.
Note: Example 6 will retrieve the first record in the admin table and display its unum, rnum and legal name.  Please keep in mind that the first record will be identified according to the primary index on the table.
	WHERE  expression
The WHERE clause limits record retrieval based on a condition (expression).
FIND     [FIRST/NEXT/PREV/LAST]     table-name      WHERE  condition
NO-LOCK.
EXAMPLE 7:
FIND FIRST admin WHERE rnum > 0 NO-LOCK.
DISPLAY unum rnum legal_n.
Note: Example 7 will retrieve the first record in the admin table with a RUN that is greater than 0; it retrieves the first subunit. Please keep in mind that the first record is still identified according to the primary index on the table.
EXAMPLE 8:
FIND admin WHERE unum = 4006 and rnum = 0 NO-LOCK.
DISPLAY unum rnum legal_n.
Note: Since the admin table is indexed on rnum within unum, this statement will only be true for a single record.  Therefore, you don’t need to specify FIRST, NEXT, PREV or LAST.  The use of one of these words can be eliminated as long as the associated WHERE clause is specific enough to identify a single record.
Exercise 4:
1.	Using the FIND command, retrieve the last record from the ADMIN table whose initial liability date is after 12/31/2003.  If you need to reference the database definition for the ADMIN table, use EDITINSERT FIELDS.
2.	Display the account number, name, and initial liability date.
3.	Check the syntax and run the program.
4.	Save the program as “find1.p”.
	
	OF  table-name
The OF table-name option can be used with the FIND statement when a direct relationship exists between two tables.  The tables specified in the OF clause must have the cross-referencing field names in common.  The relationship requires that the key fields be defined as a UNIQUE index in one of the tables.
EXAMPLE 9:
FOR EACH admin WHERE tax_zip = ‘04330’ NO-LOCK:
FIND FIRST quarterly OF admin NO-LOCK.
DISPLAY admin.unum admin.rnum legal_n tax_zip m1emp m2emp m3emp.
END.  /* for each admin */
Note: Example 9 will result in:
•	The FOR EACH will search the admin table and select each account having a zip code of 04330, bypassing accounts with any other zip code.
•	As each account is selected, the FIND will select the most recent quarterly record associated with that account.  Although there are multiple quarters for each account, the most recent will be selected because the program asks for the FIRST quarterly.  The quarterly table is indexed by descending yr/qtr within ascending unum/rnum, thereby causing the first occurrence to be the most recent quarter for that account.
•	The requested information will be displayed for that account.
•	Then, the END statement tells PROGRESS to go back and look for another admin record with a zip code of 04330.  When there are no more accounts with a zip code of 04330, PROGRESS stops processing and the procedure ends.
•	Note that when multiple tables are used, the field names that are common to both need to be qualified with “table-name”.  This enables PROGRESS to determine which field is being referenced.
•	The FIND quarterly OF admin phrase can be used because both tables contain the fields unum and rnum and the combined unum, rnum is a unique key in the admin table.
Exercise 5:
1.	Use the FOR EACH command to retrieve all records from the ADMIN table whose initial liability date is after 12/31/2003.
2.	Within the FOR EACH loop, FIND the most recent QUARTERLY record having the same account number as the selected ADMIN record.
3.	Display the account number, year, quarter, name, initial liability date, status code (status_cd), and all 3 months of employment.  If you need to reference the database definition for the tables, use EDITINSERT FIELDS.
4.	Note:  Remember to qualify unum and rnum with a table name, since they are common to both tables.
5.	Check the syntax and run the program.
6.	Save the program as “findqofa.p”.
	
An alternative to coding the OF phrase is to identify the fields on which you want to match the tables using the WHERE clause.  This enables you to specifically identify the record you want to retrieve.  If “EXAMPLE 9” is modified in the following manner, you can identify the specific year and quarter for the record to be retrieved from the quarterly table.
FOR EACH admin WHERE tax_zip = ‘04330’ NO-LOCK:
FIND quarterly WHERE quarterly.unum = admin.unum AND 
                                         quarterly.rnum = admin.rnum AND
                                         quarterly.yr = 2003 AND
                                         quarterly.qtr = 1  NO-LOCK.
DISPLAY admin.unum admin.rnum legal_n tax_zip m1emp m2emp m3emp.
END.  /* for each admin */

Note: When using this coding format, you need to make sure that your FIND is specific enough that it will return only one record.
	Controlling Error Processing with FIND
PROGRESS provides default error processing when the record specified in the FIND statement does not exist.  However, you may not want to use the PROGRESS default processing.  PROGRESS contains statements that enable you to control what happens when a record is not found.
	NO-ERROR
The NO-ERROR keyword is placed immediately following the NO-LOCK keyword in a FIND statement to tell PROGRESS that you want to control the error processing within the program.
FIND     [FIRST/NEXT/PREV/LAST]     table-name     [OF table-name] 
[WHERE expression]     [USE-INDEX index]     NO-LOCK    NO-ERROR

IF   [NOT]   AVAILABLE  table-name  THEN   [DO]

IF AVAILABLE table-name is used to determine if the record has been found in the table identified by table-name.  THEN [DO]  tells PROGRESS that you want to execute the statement(s) that follow when the record exists.
EXAMPLE 10:
FIND admin WHERE unum = 9008 and rnum = 101
NO-LOCK  NO-ERROR.
IF AVAILABLE admin THEN
DISPLAY unum rnum legal_n init_liab_dte.
Note: The FIND will look for the ADMIN record that has the specified account number.  If it is found, the account number, name and initial liability date will be displayed.  If it is not found nothing will happen, since the program hasn’t told PROGRESS what to do if the record is not available.  In this situation, PROGRESS will not provide a default error statement.  See Chapter 5 for discussion on Conditional Processing (IF…THEN…ELSE).
Exercise 6:
1.	Modify the program you created in Exercise 5 to use the NO-ERROR option.  Search for the quarterly record using the WHERE clause rather than the OF phrase.
2.	Use the IF AVAILABLE phrase to check for the existence of the record before issuing the DISPLAY statement.
3.	Check the syntax and run the program.
4.	Save the program as “findwnoerr.p”.

	
CHAPTER 4:	
	Operators and Functions
	
Many options exist for performing operations and functions on database fields and variables for selection, calculations, and comparisons.  The tables below illustrate some of the options.
	Operators
	Arithmetic Operators
Arithmetic operators are used to perform calculations.
Symbol	Operation	
+	•	Unary positive
•	Adds numeric and date fields
•	Concatenates string fields and literals (non-numeric function)	
	•	Unary negative
•	Subtracts numeric and date fields	
*	Multiplies two numeric fields	
/	Divides two numeric fields, producing a decimal value	
MODULO	Determines the remainder after dividing the first number by the second number	
	Comparison Operators
Comparison Operators are used to compare the value of one field to another.
Symbol	Keyword	Operation	
=	EQ	Equal to	
<>	NE	Not equal to	
>	GT	Greater than	
<	LT	Less than	
>=	GE	Greater than or equal to	
<=	LE	Less than or equal to	
	Keywords
Keywords are used to establish a logical relationship between phrases.
Keyword	Operation	
AND	Results in TRUE only if ALL phrases are TRUE	
OR	Results in TRUE if ANY phrase is TRUE	
NOT	Negates the value of a logical operand	
	Functions
PROGRESS provides several functions for mathematical calculations and data conversion.  A few of the more common functions are included in the table that follows.
Function	Syntax	Operation	
INTEGER	INTEGER(expression)	Converts an expression of any data type into an integer.	
DECIMAL	DECIMAL(expression)	Converts an expression of any data type into a decimal.	
STRING	STRING(expression)	Converts an expression of any data type into a character string.	
SUBSTRING	SUBSTRING(string,position [,length])	Selects specific characters from a character string.	
TODAY	TODAY	Returns the current system date.	

Additional functions can be found in the PROGRESS programming manuals or online ‘Help’.  Some of them are listed below.

Mathematical Functions: 
ABSOLUTE
EXPONENT
MINIMUM
LOGARITHM
TRUNCATE
MODULO
SQUARE ROOT

Date Functions: 
DATE
DAY
MONTH
WEEKDAY
YEAR
TIME

String Functions and Operators: 
BEGINS
MATCHES
LENGTH
CAPS
LC
TRIM
ENTRY
NUM-ENTRIES
	Precedence
PROGRESS uses a specific order when evaluating an expression.  It is important to keep this in mind when using functions and operators.

Order of evaluation: 
1.	Functions
2.	Expressions in parentheses (innermost to outermost)
3.	Operators in the following order:
a)	Unary
b)	Multiply, divide, modulo
c)	Add, subtract
d)	MATCHES, BEGINS, comparison operators
e)	NOT
f)	AND
g)	OR
	
CHAPTER 5:	
	Conditional Processing
	
Conditional processing enables you to perform actions on a record when certain criteria are met.  It also enables you to take action on a record when the criteria are not met.
	If…Then…Else
The IF…THEN…ELSE statement makes the execution of a statement or block of statements optional, depending on the status of the record.  If the condition following the IF evaluates to TRUE, PROGRESS executes the statements that follow the THEN statement.  If it is FALSE, PROGRESS executes the statements that follow the ELSE statement.
Statement syntax:
IF  expression  THEN   {block/statement}    [ELSE   {block/statement}]

In its simplest form, the IF statement contains the following elements:
IF  expression  THEN  statement. 
EXAMPLE 1:
IF quarterly.m3emp >= 1500 THEN
	DISPLAY unum rnum yr qtr m1emp m2emp m3emp.
Note: This will cause records having 1500 or more employees in month 3 of the quarter to be displayed.  Of course, in an actual program, you would need a FOR EACH statement to retrieve the records from the quarterly table before executing this IF statement.
FOR EACH quarterly NO-LOCK:
IF quarterly.m3emp >= 1500 THEN
DISPLAY unum rnum yr qtr m1emp m2emp m3emp.
END.
	ELSE  {block/statement}
The ELSE statement will be executed when the IF condition is not true.  Any processing associated with the ELSE will be performed.
EXAMPLE 2:
FOR EACH quarterly NO-LOCK:
 	IF quarterly.m3emp >= 1500 THEN
		DISPLAY unum rnum yr qtr m1emp m2emp m3emp.
	ELSE
		DISPLAY unum rnum yr qtr “Under 1500”.
	END.  /*  for each quarterly */
Note: In Example 2, any quarterly record having month 3 employment that is less than 1500 will execute the ELSE statement, displaying the account number, year, quarter and the message “Under 1500”.
Exercise 1:
1.	Read all of the quarterly records.
2.	If the status code is 1, display “Active” and appropriate fields from the quarterly table.  Otherwise, display “Inactive or Pending” and appropriate fields from the quarterly table.
3.	Check the syntax and run the program.
4.	Save the program as “ifbasic.p”.
	
	Using Multiple Statements with IF
PROGRESS allows you to execute more than one statement after the THEN and ELSE statements.  To process multiple statements, use DO/END to define the beginning and end of the series of statements (code block) associated with each condition.
IF  expression  THEN DO:   {block}   END.   [ELSE DO:   {block}   END.]
EXAMPLE 3:
def var ame as integer no-undo.
def var rec-count as integer no-undo.
FOR EACH quarterly WHERE yr = 2003 and qtr = 2 NO-LOCK:
IF quarterly.status_cd = “1” and quarterly.m3emp >= 1000 THEN DO:
ASSIGN ame = (m1emp + m2emp + m3emp) / 3.
DISPLAY unum rnum yr qtr ame. 
END.
ELSE DO:
IF quarterly.status_cd = “1” THEN DO:
ASSIGN rec-count = rec-count + 1.
DISPLAY unum rnum yr qtr “Under 1000”.
END.  /* status_cd = 1 */
END.  /* else do */
END.  /*  for each quarterly */
DISPLAY  “Total Under 1000” rec-count.
	Nesting Multiple IF Statements
	PROGRESS allows you to place IF statements within IF statements.  This is called “nesting” or “nested if statements”.  The syntax of the statement is the same, regardless of the number of IF statements used.
EXAMPLE 4:
def var cnt as integer no-undo.
FOR EACH quarterly WHERE yr = 2004  NO-LOCK:
IF status_cd = “1” THEN DO:
IF quarterly.m3emp >= 1500 THEN DO:
FIND admin WHERE admin.unum = quarterly.unum and
                                    admin.rnum = quarterly.rnum 
                                    NO-LOCK NO-ERROR.
IF AVAILABLE admin THEN
DISPLAY admin.unum admin.rnum legal_n yr qtr
m1emp m2emp m3emp.
ELSE
DISPLAY quarterly.unum quarterly.rnum
                 “Quarterly Missing Admin”.
END.  /* m3emp >= 1500 */
ELSE
ASSIGN cnt = cnt + 1.
END.  /* status_cd = 1 */
END.  /*  for each quarterly */
DISPLAY “Total Under 1500 “ cnt.
Note: This example demonstrates most of what this course has covered to this point.  It retrieves all of the 2004 records from the quarterly table and checks the month 3 employment of each.
If the account is active, then if the employment is equal to or greater than 1500, it FINDs the related admin record.  If the admin record exists, the account number, name, year, quarter, and 3 months of employment are displayed.  If the related admin record does not exist, the ELSE statement is executed and the quarterly account number is displayed with the message “Quarterly Missing Admin”.
Otherwise, if the employment is less than 1500, the record counter is incremented by 1.  At the end of the program, the message “Total Under 1500” is displayed followed by the record count.
EXAMPLE 5:
Look at Example 3 and revise the program to use “Nested IF” processing for the status code check to make the program more efficient.
Exercise 2:
1.	Read the admin table for all records with an initial liability date after 09/30/2003.
2.	Find the related quarterly record for 2004-1, using the where clause.
3.	If the quarterly is available, check the meei code.  If it is 1, 4 or 6, display the account number and “Single”.  If it is 2, display the account number and “Master”.  Otherwise, display the account number and “Subunit”.
4.	If it is not available, display the account number and “No Quarterly for 2004-1”.
5.	Check the syntax and run the program.
6.	Save the program as “ifnest.p”.

	
CHAPTER 6:	
	Define Statement
	
	The DEFINE statement enables you to create temporary storage areas for use with a program.  These temporary areas are of several types, including:
•	Variable – individual data item.
•	Record buffer – copy of record.
	Defining Variables
A variable is a temporary storage area for data.  It is most commonly used to store the value of a calculated field, a database field, a logical, or a record counter.  To use a variable, you must define it and give it a value.
Statement syntax:
DEFINE VARIABLE  variable-name
{AS  datatype/LIKE  field  [FORMAT  format]}
[DECIMALS  n]     [INITIAL  value(s)]     [LABEL  string(s)]
NO-UNDO
	AS  datatype
The data types available for defining variables are CHARACTER, INTEGER, DECIMAL, DATE, and LOGICAL.  The data type determines how PROGRESS stores and uses the variable.  Each data type has a default format and a default initial value.  You can, however, define both when you define the variable.
	FORMAT  format
This indicates the format of the variable you define.  This format is used for display purposes only.  The default display formats for each data type are:
Data Type	Default Display Format	
CHARACTER	X(8)	
DATE	99/99/99	
DECIMAL	->>,>>9.99	
INTEGER	->,>>>,>>9	
LOGICAL	yes/no	
	DECIMALS  n
The n indicates the number of decimal places to store for a decimal.  This number can be a 0 if no decimal places are desired.
	INITIAL  value
This keyword assigns a starting value to the variable you define.  As with FORMAT, PROGRESS provides default initial values for each data type.
Data Type	Default Initial Value	
CHARACTER	“”  (an empty character string)	
DATE	?    (unknown value - displays as blanks)	
DECIMAL	0	
INTEGER	0	
LOGICAL	no	
	LABEL  string
This is the label you want to use to identify the information when the variable is displayed.  If you do not specify a label, the variable name is used as the default.
EXAMPLE 1:
DEFINE VARIABLE rec-count AS INTEGER   INITIAL 1
                                                 LABEL “# Recs”.
Note: This variable is named “rec-count”, has a data type of integer, an initial value of 1 and a label of “# Recs”.  Since no format has been identified, it will default.

DEFINE VARIABLE first-rec AS LOGICAL   INITIAL yes.
Note: This variable is named “first-rec”, has a data type of logical and an initial	value of yes.

DEFINE VARIABLE heading AS CHARACTER   FORMAT “X(30)”.
Note: This variable is named “heading”, has a data type of character and a display format of 30 characters.
	
	LIKE  field
This phrase results in the defined variable taking on the characteristics of the field that is identified.
EXAMPLE 2:
DEFINE VARIABLE hold-date LIKE admin.init_liab_dte.
Note: This variable is named “hold-date” and has a data type and display format exactly the same as the field “admin.init_liab_dte”.
	NO-UNDO
This keyword causes PROGRESS to release the storage associated with the variable when the procedure finishes.  Otherwise, it is held until the end of the session.  Its use is recommended.
	Assigning Values to Variables
There are two ways to assign a value to a variable.
•	Using the INITIAL phrase in the DEFINE statement to provide a starting value.
•	Using the ASSIGN statement to move a value into the variable field.
Statement syntax:
ASSIGN  variable  =  value  [variable =  value…]
EXAMPLE 3:
DEFINE VARIABLE rec-count AS INTEGER   INITIAL 0   NO-UNDO.
Read records.
ASSIGN rec-count = rec-count + 1.
Note: The DEFINE statement creates a counter, giving it a starting value of 0.  The ASSIGN statement adds 1 to the counter each time it executes.

DEFINE VARIABLE first-rec AS LOGICAL   INITIAL yes   NO-UNDO.
Read records.
IF first-rec THEN DO:
	DISPLAY “The beginning record is ” unum rnum.
	ASSIGN first-rec = no.
END.
Note: The DEFINE statement creates a logical, giving it a starting value of ‘yes’. When the program encounters the first record to be processed, it displays a message to identify the account on which processing begins.  The ASSIGN statement resets the logical to ‘no’, since subsequent records will no longer be the first to be processed.

Continued on next page

EXAMPLE 3 (continued):
DEFINE VARIABLE heading AS CHARACTER   FORMAT “X(30)” 
                                               NO-UNDO.
DEFINE VARIABLE first-rec AS LOGICAL   INITIAL yes   NO-UNDO.
Read records.
IF NOT AVAILABLE quarterly THEN DO:
IF first-rec THEN DO:
ASSIGN heading = “Quarterly Records Missing on ”.
DISPLAY heading TODAY.
ASSIGN first-rec = no.
END.  /* if first-rec */
DISPLAY admin.unum admin.rnum.
END.  /* if not available quarterly */
Note: The DEFINE statement creates a field that can hold 30 characters—alphabetic, numeric or allowable special characters.  When the program encounters a missing quarterly record, it checks to determine if this is the first unavailable record it has processed.  If it is (if first-rec), the ASSIGN statement provides the character string value for the heading and the DISPLAY statement displays that heading followed by today’s date.  (TODAY is a system variable that always contains the value of today’s date.)  The logical, first-rec, is set to ‘no’ and the account number from the admin record is displayed.  Notice that the DISPLAY for the account number is outside of the DO/END loop for first-rec.  This will cause the statement to execute each time a quarterly record is unavailable, not only when it is the first record.
	Assigning Values to Variables in Groups
The ASSIGN statement can be used to assign values to several variables at a time.  This is preferred when several variables need to be changed at the same time because the code is easier to read and it speeds processing.
EXAMPLE 4:
IF first-rec THEN DO:
ASSIGN heading = “Quarterly Records Missing on ”
first-rec = no.
DISPLAY heading TODAY.
END.  /* if first-rec */
Note: This code is taken from the final part of Example 3 above.  You will notice that the ASSIGN statements have been consolidated into a single statement.  When multiple assignments are done in a single statement, the period is placed at the end of the final assignment.  This tells PROGRESS that the statement is finished.
Exercise 1:
Create a program that will count all of the open status quarterly records for 2004-3 and accumulate the total employment for the quarter.  Exclude subunits.

1.	Define variables to hold the record count and the total employment.
2.	Read the quarterly table for all 2004-3 records that are not subunits.
3.	Check for an open status, add the employment numbers to the total employment and increment the record counter by 1.
4.	At the end of the program, display the total record count and total employment.
5.	Check the syntax and run the program.
6.	Save the program as “defvar.p”.
	
	Defining Record Buffers
When you retrieve a record from a database table, PROGRESS stores a copy of that record in a storage area called a ‘record buffer’.  This is simply a holding area for the record information so that PROGRESS doesn’t need to read the database each time the same record is referenced.  

By default, PROGRESS uses one record buffer for each table that you reference in a procedure.  Since each buffer can contain a copy of only one record from a single table, you cannot compare two records from the same table using this default record buffer.  If you need more than one record at a time from the same table, you can define additional record buffers using the DEFINE BUFFER statement.
Statement syntax:
DEFINE BUFFER  buffer-name  FOR  table-name.

Buffer-name is a name that you assign to the additional record buffer.  Generally, the name should contain some reference to the table with which it is associated and identify the buffer’s contents. 
EXAMPLE 5:
DEFINE BUFFER  priorqtr  FOR  quarterly.
Note: The record buffer ‘priorqtr’ will contain the previous quarter’s information for the quarterly record that is in the default record buffer.
EXAMPLE 6:
DEFINE BUFFER priorqtr FOR quarterly.
FOR EACH quarterly WHERE quarterly.yr = 2004 and 
                                       quarterly.qtr = 1  NO-LOCK:
FIND priorqtr WHERE priorqtr.unum = quarterly.unum and
                                      priorqtr.rnum = quarterly.rnum and
                                                  priorqtr.yr = 2003 and
                                                  priorqtr.qtr = 4  NO-LOCK  NO-ERROR.
IF AVAILABLE priorqtr THEN
Processing goes here.
END.
Note: The default record buffer contains the information on the quarterly record for 2004-1, while the ‘priorqtr’ record buffer contains the information on the quarterly record for 2003-4.  You can now compare the field values of the two records.
An alternative to coding  ‘priorqtr.yr = 2003’ is 
                             ‘priorqtr.yr = quarterly.yr – 1’.  
This, however, does require additional processing because it is performing a calculation.
Exercise 2:
Create a program to compare the county code from 2004-1 with the county code from 2003-4 for open accounts.  If it has changed, display the account number and the old and new county codes.

1.	Define a record buffer for the quarterly table to hold the previous quarter’s information.
2.	Read all of the 2004-1 records in the quarterly file.
3.	If the account is open, find the corresponding record for 2003-4.
4.	Compare the 2004-1 county code to the 2003-4 county code.  If they are not the same (not equal, <>), display the information.
5.	Check the syntax and run the program.
6.	Save the program as “defbuf.p”. 
	
	Defining Output Streams
PROGRESS uses a default output stream to display data; however, you can define additional output streams as needed.  This DEFINE is discussed in Chapter 7: Generating Reports.

CHAPTER 1:	
	
CHAPTER 7:	
	Generating Reports
	
Retrieving data from the database is only useful if you can present it in a way that is readable and useable.  PROGRESS defaults all output to the terminal or PC screen.  In this chapter you will learn how to produce a report and send it to an output file.
	Directing Output to a File
The OUTPUT TO statement will redirect output to a destination other than the screen.
Statement syntax:
OUTPUT   [STREAM  stream-name]   TO   file-name   [parameters]

In its simplest form, the statement requires the following elements:
OUTPUT  TO  file-name.
EXAMPLE 1:
OUTPUT TO  report1.txt.
Note: This will direct the output to a file named ‘report1.txt’ and place it in your PROGRESS working directory.
	STREAM  stream-name
Identifies the specific stream name to which you want to write output.  If no stream is specified, PROGRESS uses its default output stream.  To use a stream other than the default, the stream must be defined earlier in the program.  Additional output streams are only necessary if you are generating multiple reports from a single program.
	Parameters
PROGRESS has many different parameters that cause actions to be taken during the output process.  Some of the more common ones are listed in the table below.
Parameter	Action	
PAGED	Formats the output into pages.  The default lines per page is 56.	
PAGE-SIZE {constant}	Specifies the number of lines per page.  This is not required if the default of 56 is used.	
PAGE STREAM	Causes the output to start a new page.	
EXAMPLE 2:
OUTPUT TO  report1.txt  PAGED.
	DISPLAY Statement
The DISPLAY statement moves the data to the specified output destination.  If no output destination is specified, PROGRESS defaults to the screen.
Statement syntax:
DISPLAY  [STREAM stream-name]
expression [format-phrase] / SPACE [(n)] / SKIP [(n)]
[(aggregate-phrase)]     [WITH  [WIDTH n / n COLUMN …]]

In its simplest form, the statement requires the following elements:
DISPLAY  table-name / field-name
EXAMPLE 3:
DISPLAY quarterly.
Note: This will display all of the fields in the quarterly record to the screen.  PROGRESS will also default the screen formatting. 
EXAMPLE 4:
DISPLAY unum rnum yr qtr status_cd.
Note: This will display the specified fields to the screen in PROGRESS’ default screen format.
	Expression  [format-phrase]
Identifies a database field name, variable, or constant.  The format phrase can be used to represent the format in which you want to display the contents of expression.  When used this way, the syntax is “FORMAT string”, where the value of string is the display format enclosed in quotation marks.
EXAMPLE 5:
DISPLAY STREAM outstream 
                     unum rnum admin.legal_n FORMAT “x(20)”.
Note: This will display the specified fields to a predefined stream named “outstream”.  Only the first 20 characters of the employer’s name will be displayed.
EXAMPLE 6:
DISPLAY unum rnum tot_wg FORMAT “ZZ,ZZZ,ZZ9.99”.
Note: This will display the specified fields to the default output stream.  The total wages will be displayed with leading zeroes suppressed, commas and 2 decimal places.  If the value is zero, it will display as ‘0.00’.
	Aggregate-phrase
Identifies one or more aggregate values to be calculated.  The value can be optionally based on a change in a break group.  This will be discussed later in this chapter.
	SPACE [(n)]
N identifies the number of spaces to be inserted before the next item is displayed.  If no value is assigned to n, PROGRESS defaults to 1. 
	SKIP [(n)]
N identifies the number of blank lines to be inserted before the next line is displayed.  If no value is assigned to n, PROGRESS skips to the next line.
EXAMPLE 7:
DISPLAY unum SPACE rnum SPACE(5) legal_n SKIP tax_cty “, ” tax_st.
Note: This will display the UI#, a single space, the RUN followed by 5 spaces, and the employer’s legal name on the first line.  The city and state will be displayed on the next line because of the SKIP, separated by a comma and a space (“, “).
	WITH  [WIDTH n / n COLUMN] 
The WITH phrase can be used to set additional parameters to further control the display format.  The WIDTH parameter is used to override the default page width and is useful when your report requires a landscape layout.  The COLUMN parameter is used to display the data in columnar format and is useful when the display is hard to read in PROGRESS’ default format.
EXAMPLE 8:
DISPLAY fields WITH WIDTH 130.
Note: This will display the specified fields for each record across the report page on 1 line that can be 130 characters wide.

DISPLAY admin WITH 1 COLUMN.
Note: This will display each admin record in a single column, 1 field on each line.
Exercise 1:
Create a program that will read the records from the admin table and display the fields from the first 10 records on the screen in a single column.

1.	Define a variable to count the records.
2.	Read the admin table.
3.	Display the record if less than 11 records have been displayed.
4.	Check the syntax and run the program.
5.	Save the program as “dispcol.p”.
	
Exercise 2:
Create a program that reads both the admin and quarterly tables.  Display whatever fields you desire, but make sure to include a “FORMAT” statement for at least one of them.  Use SPACE and SKIP to help format the report.  Output the report to a file named ‘myrept.txt’.  Experiment with what you have learned, using any statements/commands we have covered in the course to this point.
	
	Defining Output Streams
The DEFINE STREAM statement can be used to define additional output streams.  PROGRESS allows the definition of up to five additional streams in a single program.
Statement syntax:
DEFINE STREAM stream-name.

The stream-name that you assign will always be associated with this output stream.
EXAMPLE 9:
DEFINE STREAM reptstream.
Note: “Reptstream” is the output stream being defined.
EXAMPLE 10:
DEFINE STREAM reptstream.
OUTPUT STREAM reptstream TO report1.txt.
Process records.
DISPLAY STREAM reptstream field-names.
Note: This will cause the output to be directed to “report1.txt” whenever “reptstream” is the referenced output stream.
	Aggregating Totals/Performing Mathematical Functions
The aggregate-phrase in the DISPLAY statement enables you to perform calculations on your numeric output.  This phrase can only be applied to a break group or an expression that changes.  Some of the aggregation functions are listed below:
AVERAGE
COUNT
MAXIMUM
MINIMUM
TOTAL
SUB-AVERAGE
SUB-COUNT
SUB-MAXIMUM
SUB-MINIMUM
SUB-TOTAL

Aggregate-Phrase Syntax:
function   [LABEL  function-identifier]   [BY  break-group]
	LABEL  function-identifier
Assigns a label to the aggregated value for display on the report.
	BY  break-group
Applies the aggregation to the BREAK group specified in a FOR EACH statement.
EXAMPLE 11:
FOR EACH quarterly WHERE yr = 2004 AND status_cd = “1” NO-LOCK:
DISPLAY unum rnum tot_wg (AVERAGE).
END.
Note: This will display a single report line with the unum, rnum and total wages of each active quarterly account for 2004.  At the end of the report, the average of the total wages will be displayed.

FOR EACH quarterly NO-LOCK USE-INDEX yqur WHERE yr = 2004
AND status_cd = “1” BREAK BY qtr:
DISPLAY qtr unum rnum tot_wg (AVERAGE  LABEL “Quarterly Avg” BY qtr).
END.
Note: This will display a single report line with the qtr, unum, rnum and total wages of each active quarterly account for 2004 by quarter.  At the end of each quarter, the average of the total wages for that quarter will be displayed with the label “Quarterly Avg”.
Exercise 3:
Create a program that will read the quarterly table for active masters that have taxable wages greater than 0 in 2004 and calculate the TOTAL taxable wages for each quarter (use the index “yqur”).  Display the quarter, unum, rnum and taxable wages for each record with a total for taxable wages at the end of each quarter.  Save the program as “tottax.p”.
	
	FIRST-OF and LAST-OF Functions
The output from Exercise 3 repeats the quarter on every line.  When using a BREAK BY phrase, you can use the FIRST-OF and LAST-OF functions to control when the quarter is displayed.
FIRST-OF/LAST-OF Syntax:
FIRST-OF/LAST-OF (break-group)
EXAMPLE 12:
FOR EACH quarterly NO-LOCK USE-INDEX yqur WHERE yr = 2004
AND status_cd = “1” BREAK BY qtr:
IF FIRST-OF (qtr) THEN DISPLAY qtr.
DISPLAY unum rnum tot_wg (AVERAGE  LABEL “Quarterly Avg” BY qtr).
END.
Note: The FIRST-OF phrase will cause the quarter to be displayed only on the first occurrence of the quarter.  It will not be repeated on each line of the report.  Conversely, the LAST-OF phrase would cause the quarter to be displayed only on the last occurrence of the quarter.
Exercise 4:
Modify Exercise 3 to use the FIRST-OF and/or LAST-OF function(s).
	
	Using ACCUMULATE and ACCUM
You use ACCUMULATE to carry running totals/aggregate values and ACCUM to access those values for display in a report. 
ACCUMULATE  Statement Syntax:
ACCUMULATE  expression (aggregation/function)

ACCUM  Function Syntax:
ACCUM aggregation/function  expression
EXAMPLE 13:
FOR EACH quarterly WHERE yr = 2004 AND qtr = 1 NO-LOCK:
IF status_cd = “1” and m3emp > 0 THEN
ACCUMULATE m3emp (TOTAL AVERAGE  MAXIMUM).
END.
DISPLAY “Month 3 Employment Information for 2004-1”.
DISPLAY “Total:          “   (ACCUM TOTAL quarterly.m3emp) SKIP(1)
      “Average:     “  (ACCUM AVERAGE quarterly.m3emp) SKIP(1)
      “Maximum:  “  (ACCUM MAXIMUM quarterly.m3emp) SKIP(1)
            WITH NO-LABELS.
Exercise 5:
Using the ACCUMULATE and ACCUM functions, create a report that will display the average employment for month 2 of 2004-1 and give a count of the records.  Hint: The aggregations you need are AVERAGE and COUNT.
	
	EXPORT Statement
The EXPORT statement can be used to output data to a file in standard character format.  The file will be output to the destination specified.  You can, optionally, specify a delimiting character between fields.
Statement syntax:
EXPORT   [STREAM stream-name]    [DELIMITER  character]   field-names
	STREAM  stream-name
The name of a previously defined output stream
	DELIMITER  character
The character to be used to separate the data items in the file.  The value of character must be a quoted single character.  If no delimiter is specified, PROGRESS defaults to a space.
EXAMPLE 14:
EXPORT STREAM filestream DELIMITER “,”
unum rnum m1emp m2emp m3emp tot_wg tax_wg.
Note: This will output a file to the destination for filestream.  The file will contain a record for each occurrence of the fields listed.  Commas will separate the fields within each record.
Exercise 6:
Create a program that will export data to a file that will be used as input to a selective run of the EQUI program.  The fields that should be included in the file are state fips code, unum, rnum, year, and quarter.

NOTE: You will need to read the first record in the “state-info” table to find the state fips code.

CHAPTER 1:	
	
	Index

A
ACCUM statement, 7-6
ACCUMULATE statement, 7-6
Aggregate-phrase, 7-3
Aggregate-phrase with DISPLAY, 7-5
Aggregation functions, 7-5
Arithmetic operators, 4-1
ASSIGN statement, 6-3
Assigning values to variables, 6-3
Assigning values to variables in groups, 
6-4
AVAILABLE function, 3-7
B
Buffer. See Record buffer
BY option, 3-3, 7-5
C
Checking program syntax, 2-7
Checking, compiling, and running a program, 2-7
Comparison operators, 4-1
Compile, 2-7
Conditional processing, 5-1
Controlling error processing with FIND, 3-6
Create a new program, 2-1
Cutting, copying and pasting text, 2-4
D
Database, 1-1
Index, 1-2
Key, 1-2
Foreign key, 1-2
Primary key, 1-2
Table, 1-1
Field, 1-1
Record, 1-1
Database definitions, 1-1
Database tables
Contents and relationships, 2-8
Reports, 2-8
Structure, 2-8
Viewing, 2-8
Date functions, 4-2
Deadly Embrance, 3-3
Defining output streams, 6-6, 7-4
Defining record buffers, 6-5
Defining variables, 6-1
DELIMITER character, 7-7
Directing output to a file, 7-1
Display statement, 7-2
E
Edit buffer, 2-8
List, 2-8
Next, 2-8
Previous, 2-8
Editing a program, 2-4
ELSE statement, 5-1
Entering text, 2-4
Error messages, 2-7
Help, 2-7
Recent, 2-7
EXPORT statement, 7-7
F
Field selector screen, 2-6
FIND statement, 3-1, 3-3
FIRST-OF function, 7-6
FOR EACH statement, 3-1
Functions, 4-2
ACCUM, 7-6
AVAILABLE, 3-7
Date, 4-2
FIRST-OF, 7-6
IF … THEN, 3-7
LAST-OF, 7-6
Mathematical, 4-2
Operators, 4-2
String, 4-2
G
Generating reports, 7-1
I
IF … THEN … ELSE statement, 5-1
Inactivating or commenting text, 2-5
INITIAL
keyword, 6-3
value, 6-2
Insert fields, 2-6
Inserting a field name, 2-6
K
Keywords, 4-1
L
LABEL option, 7-5
LAST-OF function, 7-6
LIKE field, 6-2
M
Mathematical functions, 4-2
Multiple statements
Define beginning and end, 5-2
IF, 5-2
Nesting multiple, 5-3
N
Nesting multiple IF statements, 5-3
NO-ERROR option, 3-6
NO-LOCK, 3-3
NO-UNDO option, 6-3
O
OF option, 3-5
Opening an existing program, 2-2
Operators
Arithmetic, 4-1
Comparison, 4-1
Options
BY, 3-3, 7-5
LABEL, 7-5
NO-ERROR, 3-6
NO-UNDO, 6-3
OF, 3-5
WITH, 7-3
Order of evaluation, Expressions, 4-3
Output stream name, 7-7
Output streams
Defining, 6-6
OUTPUT TO statement, 7-1
P
PAGE STREAM parameter, 7-1
PAGED parameter, 7-1
PAGE-SIZE parameter, 7-1
Parameters
OUTPUT TO, 7-1
PAGE STREAM, 7-1
PAGED, 7-1
PAGE-SIZE, 7-1
WIDTH, 7-3
Precedence, 4-3
Prefixes, 2-6
Procedure editor, 2-1
Program syntax, 2-7
R
Record buffers
Defining, 6-5
Relational database structure, 1-1, 1-2
Relational model, 1-2
Reports
Generating, 7-1
Retrieving database records, 3-1
Running a program, 2-7
S
Saving a program, 2-3
Searching text, 2-5
Selecting text, 2-4
SKIP with DISPLAY, 7-3
SPACE with DISPLAY, 7-3
Statements
ACCUMULATE, 7-6
ASSIGN, 6-3
DEFINE, 6-1
DEFINE BUFFER, 6-5
DEFINE STREAM, 7-4
DISPLAY, 7-2
Aggregate-phrase, 7-3
Expressions, 7-2
SKIP, 7-3
SPACE, 7-3
WIDTH, 7-3
WITH, 7-3
DISPLAY, Aggregate totals/performing mathematical functions, 7-5
ELSE, 5-1
EXPORT, 7-7
FIND, 3-1, 3-3
FIND, Controlling error processing, 3-6
FOR EACH, 3-1
IF … THEN … ELSE, 5-1
OUTPUT TO, 7-1
Parameters, 7-1
STREAM name, 7-1
Store value of calculated fields, 6-1
STREAM name, 7-1, 7-7
String functions and operators, 4-2
T
Table relations, 2-8
V
Variables
AS datatype, 6-1
Assigning group values, 6-4
Assigning values, 6-3
DECIMALS, 6-2
Default display formats, 6-1
Defining, 6-1
Display label, 6-2
FORMAT, 6-1
Formatting numbers, 6-2
INITIAL value, 6-2
LABEL string, 6-2
LIKE field, 6-2
W
WHERE clause, 3-2, 3-4, 3-6
WITH option, 7-3